package parsetm;
import java.lang.*;
import java.io.*;//for read from file
import java.util.*;//for the Map
import java.lang.Object.*;
//import org.biojava.bio.seq.*;
//import org.biojava.bio.symbol.*;
//import org.biojava.bio.BioException;
//borde kolla att namnen �r h�gst 10 stora

//read from a file called with the main parameter
public class parseTM
{
/*
private static void translate(Map m,List lst){
  Integer nr= new Integer(m.size());
  String nr_prot = nr.toString();
  String name_prot;
  String sequence_prot;
  int order_index = 0;
  while(order_index < nr.intValue()){
    name_prot = (String) lst.get(order_index);
    sequence_prot = new String( (String)m.get(name_prot));
    try {
      sequence_prot = translateDNAToProtein(sequence_prot);

    }catch(BioException ex ){
    }
    m.put(name_prot, sequence_prot);
    order_index++;
  }
}

private static String translateDNAToProtein(String DNA) throws BioException {
  String amino = new String();
  if( DNA.length()%3 != 0 ){
    throw new BioException("DNA string length must be divisible by 3");
  }
  if( DNA.indexOf("N")==-1 && DNA.indexOf("n")==-1 ){
    SymbolList symL = DNATools.createDNA(DNA);
    symL = RNATools.transcribe(symL);
    symL = RNATools.translate(symL);
    return symL.seqString();
  }
  System.out.println("Handling sequence with 'N's in it");
  int pos = 0;
  for(pos = 0;pos<DNA.length();pos+=3){
    String s = DNA.substring(pos,pos+3);
    if( s.indexOf("n")==-1 && s.indexOf("N")==-1 ) { // then we know there are no unknown bases in this codon
      try{
        SymbolList symL = DNATools.createDNA(s);
        symL = RNATools.transcribe(symL);
        symL = RNATools.translate(symL);
        amino = amino+symL.seqString();
      }
      catch( IllegalSymbolException ex) {
        ex.printStackTrace();
      }catch( IllegalAlphabetException ex) {
        ex.printStackTrace();
      }
    }
    else { // if the codon contains any 'N's at all, we translate it to a 'X'
      amino = amino + "X";
    }
  }
  return amino;
}
*/
  private static void read_phy(Map m,List lst,String file)
  {
    String []amino_acids;
    String []name;

    try
    {
      BufferedReader b = new BufferedReader(new FileReader(file));
      String nr=b.readLine();
      StringTokenizer t=new StringTokenizer(nr);

      //read from file nr of proteins and their length
      String nr_proteins     = t.nextToken();
      String proteins_length = t.nextToken();

      name        = new String[Integer.parseInt(nr_proteins)];
      amino_acids = new String[Integer.parseInt(nr_proteins)];

      //Read first line of each protein in the phy file
      for(int s=0;s<Integer.parseInt(nr_proteins);s++)
      {
        String aa = new String();
        String tmp = new String();
        String current_line = b.readLine();
        t = new StringTokenizer(current_line);

        String prot_name = t.nextToken();
        while(t.hasMoreTokens())
          aa = aa.concat(t.nextToken());

        name[s] = prot_name;
        lst.add(s,(String)name[s]);
        amino_acids[s]= aa;
      }

      //Parse trougth the rest of the file
      int prot=0;
      while(true)
      {

        String aa = new String();
        String current_line = b.readLine();
        if(current_line == null)break;

        if(current_line.length()==0)
        {
          current_line = b.readLine();
          if(current_line == null)break;
        }

        t=new StringTokenizer(current_line);
        while(t.hasMoreTokens())
          aa = aa.concat(t.nextToken());

        amino_acids[prot] = amino_acids[prot].concat(aa);
        if(prot<Integer.parseInt(nr_proteins)-1)
          prot++;
        else
          prot=0;
      }

      String tmp;
      //Insert name and amino acid in the Hashmap, if duplicate, add a I last in name
      for(int e=0;e<Integer.parseInt(nr_proteins);e++)
      {
        tmp = (String)m.put(name[e],amino_acids[e].toUpperCase());
        if(tmp != null)
        {
          System.out.println("Found a duplicate name: " + name[e]);
          while(m.containsKey(name[e]))
            name[e] = name[e].concat("I");
          System.out.println("have changed it to:     "+ name[e]);
          System.out.println();
          m.put(name[e],amino_acids[e].toUpperCase());
        }
      }
      //System.out.println("Inserted :" + m.size() + " sequences");
    }
    catch(IOException e)
    {
      System.out.println("Couldn't open the file");
    }

  }






  private static void read_rose(Map m,List lst,String file){

    String []amino_acids;
    String []name;
    int c1=0;

    try
    {
      BufferedReader b = new BufferedReader(new FileReader(file));
      String nr=b.readLine();
      StringTokenizer t=new StringTokenizer(nr);
      //read from file nr of proteins and their length
      String nr_proteins     = t.nextToken();
      String proteins_length = t.nextToken();
      name        = new String[Integer.parseInt(nr_proteins)];
      amino_acids = new String[Integer.parseInt(nr_proteins)];

      //Read first line of each protein in the phy file
      for(int s=0;s<Integer.parseInt(nr_proteins);s++)
      {
        String aa = new String();
        String tmp = new String();
        String current_line = b.readLine();
        t= new StringTokenizer(current_line);
        String prot_name = t.nextToken();
        while(t.hasMoreTokens())
          aa = aa.concat(t.nextToken());

        name[s] = prot_name;
        amino_acids[s]= aa;
      }

      //Parse trougth the rest of the file
      int prot=0;
      while(true)
      {
        String aa = new String();
        String current_line = b.readLine();
        if(current_line == null)break;

        if(current_line.length()==0)
        {
          current_line = b.readLine();
          if(current_line == null)break;
        }

        t=new StringTokenizer(current_line);
        while(t.hasMoreTokens())
          aa = aa.concat(t.nextToken());

        amino_acids[prot] = amino_acids[prot].concat(aa);
        if(prot<Integer.parseInt(nr_proteins)-1)
          prot++;
        else
          prot=0;
      }

      String tmp;
      //Insert name and amino acid in the Hashmap, if duplicate, add a I last in name
      for(int e=0;e<Integer.parseInt(nr_proteins);e++)
      {
        tmp = (String)m.put(name[e],amino_acids[e].toUpperCase());
        lst.add(e,(String)name[e]);
        if(tmp != null)
        {
          System.out.println("Found a duplicate name: " + name[e]);
          while(m.containsKey(name[e]))
            name[e] = name[e].concat("I");
          System.out.println("have changed it to:     "+ name[e]);
          System.out.println();
          m.put(name[e],amino_acids[e].toUpperCase());
          lst.add(e,(String)name[e]);
        }
      }
    }
    catch(IOException e)
    {
      System.out.println("Couldn't open the file");
    }

  }


private static void read_fasta(Map dnaMap, List lst,String file)
{
  String codons       = new String();
  String name         = new String();
  String tmp          = new String();
  String current_line = new String();
  StringTokenizer t;
  int i=0;
  try
  {
    BufferedReader b = new BufferedReader(new FileReader(file));
    name = new String();
   //read file to String
   String f = new String();
   while(true){
      current_line = b.readLine();
      if(current_line == null) break;
      t=new StringTokenizer(current_line);
      while(t.hasMoreTokens())
        f = f.concat(t.nextToken());
      //add a '>' before the sequense (a character reserved in the fasta format)
      if(current_line.startsWith(Character.toString('>')))
        f = f.concat(">");
   }
   t = new StringTokenizer(f,">");
   while(t.hasMoreTokens()){
      name  = t.nextToken();
      codons = t.nextToken();
      tmp = (String)dnaMap.put(name,codons.toUpperCase());
      lst.add(i,(String)name);
      if(tmp != null)
      {
        System.out.println(  "Found a duplicate name: " + name);
        while(dnaMap.containsKey(name))
          name = name.concat("I");
          System.out.println("have changed it to:     "+ name);
          System.out.println();
          dnaMap.put(name,codons.toUpperCase());
          lst.add(i,(String)name);
      }
      i++;
   }
  }
  catch(IOException e)
  {
    System.out.println("Couldn't open the file");
  }
}

private static void find_tm(Map m, List lst){
  double hydro[] = new double ['Z'];
  hydro['F'] = 5.0;
  hydro['W'] = 4.88;
  hydro['L'] = 4.76;
  hydro['I'] = 4.41;
  hydro['M'] = 3.23;
  hydro['V'] = 3.02;
  hydro['C'] = 2.5;
  hydro['Y'] = 2.0;
  hydro['A'] = 0.16;
  hydro['T'] = -1.08;
  hydro['E'] = -1.5;
  hydro['D'] = -2.49;
  hydro['Q'] = -2.76;
  hydro['R'] = -2.77;
  hydro['S'] = -2.85;
  hydro['G'] = -3.31;
  hydro['N'] = -3.79;
  hydro['H'] = -4.63;
  hydro['P'] = -4.92;
  hydro['K'] = -5.0;
  double helic[] = new double ['Z'];
  helic['F'] = 1.26;
  helic['W'] = 1.07;
  helic['L'] = 1.28;
  helic['I'] = 1.29;
  helic['M'] = 1.22;
  helic['V'] = 1.27;
  helic['C'] = 0.79;
  helic['Y'] = 1.11;
  helic['A'] = 1.24;
  helic['T'] = 1.09;
  helic['E'] = 0.85;
  helic['D'] = 0.89;
  helic['Q'] = 0.96;
  helic['R'] = 0.95;
  helic['S'] = 1.0;
  helic['G'] = 1.15;
  helic['N'] = 0.94;
  helic['H'] = 0.97;
  helic['P'] = 0.57;
  helic['K'] = 0.88;
  int window[] = new int ['Z'];
  for ( int i = 0; i < 'Z'; i++ ){
    window[i] = 0;
  }
  Integer nr = new Integer(m.size());
  String nr_prot = nr.toString();
  String name_prot;
  StringBuffer sequence_prot;
  String subseq;
  int order_index = 0, tm_lenght;
  int front = 0, rear = 0, window_size = 17;
  int begin = 0, end = 0, regions = 0;
  boolean in_tm = false, finished = false, looking = true;
  while( order_index < nr.intValue() ){
    begin = 0;
    end = 0;
    regions = 0;
    name_prot = (String) lst.get( order_index );
    System.out.println("Name: " + name_prot);
    sequence_prot = new StringBuffer( ( String ) m.get( name_prot ));
    int lenght = sequence_prot.length();
    looking = true;
    in_tm = false;
    finished = false;
   /* System.out.println("Front: " +front);
    System.out.println("Rear: " +rear);
    System.out.println("Looking: " +looking);
    System.out.println("In_tm: " +in_tm);
    System.out.println("Finished: " +finished);
    System.out.println("Begin: " +begin);
    System.out.println("End: " +end);
    System.out.println("Regions: " +regions);
    System.out.println("Window size: " +window_size);
    System.out.println("Lenght: " +lenght);*/
    for ( front = 0; front < window_size; front++ ){
      window[sequence_prot.charAt(front)]++;
    }
    rear = 0;
    for ( front = window_size; front < lenght; front++ ){
      window[sequence_prot.charAt(front)]++;
      window[sequence_prot.charAt(rear)]--;
      if ( window[sequence_prot.charAt(rear)] < 0 ){
        System.out.println("Below zero");
      }
      if ( looking == true ){
        if ( calc_tm(hydro, helic, window, window_size) ){
          looking = false;
          finished = false;
          in_tm = true;
          begin = rear;
        }
      }
      if ( in_tm == true ){
        end = front;
        if ( ! calc_tm(hydro, helic, window, window_size) || end - begin >= 35 ){
          in_tm = false;
          looking = false;
          finished = true;
        }
      }
      if ( finished == true ){
        if ( rear <= end ){
          if ( calc_tm(hydro, helic, window, window_size) ){
            if ( front - end < 5 && end - begin < 35 ){
              end = front;
              finished = false;
              in_tm = true;
              looking = false;
            }
            else{
              if ( end - begin < 26 ){
                end = front;
                finished = false;
                in_tm = true;
                looking = false;
              }
            }
          }
        }
        else {
          if ( calc_tm(hydro, helic, window, window_size) ){
            regions++;
            tm_lenght = end - begin -3;
            System.out.println("Lenght: " + tm_lenght);
            subseq = sequence_prot.substring(begin+3, end);
            subseq = subseq.toLowerCase();
            sequence_prot.replace(begin+3,end,subseq);
            looking = false;
            finished = false;
            in_tm = true;
            begin = rear;
          }
          else {
            regions++;
            tm_lenght = end - begin -3;
            System.out.println("Lenght: " + tm_lenght);
            subseq = sequence_prot.substring(begin+3, end);
            subseq = subseq.toLowerCase();
            sequence_prot.replace(begin+3,end,subseq);
            looking = true;
            finished = false;
            in_tm = false;
          }
        }
      }
      rear++;
    }
    for ( rear = rear; rear < lenght; rear++ ){
      window[sequence_prot.charAt(rear)]--;
      if ( window[sequence_prot.charAt(rear)] < 0 ){
        System.out.println("Below zero");
      }
    }
    m.put(name_prot, sequence_prot.toString());
    order_index++;
    System.out.println("Regions found: " + regions);
  }
}

private static boolean calc_tm(double hydro[], double helic[], int window[], int window_size){
  double hydro_val = 0, helic_val = 0;
  hydro_val += hydro['F']*window['F'];
  hydro_val += hydro['W']*window['W'];
  hydro_val += hydro['L']*window['L'];
  hydro_val += hydro['I']*window['I'];
  hydro_val += hydro['M']*window['M'];
  hydro_val += hydro['V']*window['V'];
  hydro_val += hydro['C']*window['C'];
  hydro_val += hydro['Y']*window['Y'];
  hydro_val += hydro['A']*window['A'];
  hydro_val += hydro['T']*window['T'];
  hydro_val += hydro['E']*window['E'];
  hydro_val += hydro['D']*window['D'];
  hydro_val += hydro['Q']*window['Q'];
  hydro_val += hydro['R']*window['R'];
  hydro_val += hydro['S']*window['S'];
  hydro_val += hydro['G']*window['G'];
  hydro_val += hydro['N']*window['N'];
  hydro_val += hydro['H']*window['H'];
  hydro_val += hydro['P']*window['P'];
  hydro_val += hydro['K']*window['K'];
  if ( hydro_val / window_size <= 0.76 )
    return false;
  helic_val += helic['F']*window['F'];
  helic_val += helic['W']*window['W'];
  helic_val += helic['L']*window['L'];
  helic_val += helic['I']*window['I'];
  helic_val += helic['M']*window['M'];
  helic_val += helic['V']*window['V'];
  helic_val += helic['C']*window['C'];
  helic_val += helic['Y']*window['Y'];
  helic_val += helic['A']*window['A'];
  helic_val += helic['T']*window['T'];
  helic_val += helic['E']*window['E'];
  helic_val += helic['D']*window['D'];
  helic_val += helic['Q']*window['Q'];
  helic_val += helic['R']*window['R'];
  helic_val += helic['S']*window['S'];
  helic_val += helic['G']*window['G'];
  helic_val += helic['N']*window['N'];
  helic_val += helic['H']*window['H'];
  helic_val += helic['P']*window['P'];
  helic_val += helic['K']*window['K'];
  if ( helic_val / window_size > 1.1 )
    return true;
  return false;
}

private static void write_phy(Map m,List lst, String file){
  String ofile = file.substring( 0, file.length()-3 );
  String end = file.substring( file.length()-3, file.length() );
  if( end.equals(".phy") == true ){
    System.out.println("Input filname suffix was .phy, outputfilesuffix of new file is .andor");
    ofile = ofile.concat(".Andor");
  }
  else{
    ofile = ofile.concat(".phy");
    System.out.println("Have written to " + ofile);
  }
  try
  {

    BufferedWriter bw = new BufferedWriter(new FileWriter(ofile));
    //write nr of proteins and their length

    //get number through map
    Integer nr= new Integer(m.size());
    String nr_prot = nr.toString();

    //get length through set
    Set m_keys = m.keySet();
    Iterator i = m_keys.iterator();
    String key = (String)i.next();
    String value = (String) m.get(key);
    String length_prot = new Integer(value.length()).toString();

    //Create the first row with right size
    StringBuffer b1= new StringBuffer(nr_prot).reverse();
    while(b1.length()<6)
      b1=b1.append(" ");
    StringBuffer b2= new StringBuffer(length_prot).reverse();
    while(b2.length()<7)
      b2=b2.append(" ");
    String first_row =b2.append(b1).reverse().toString();
    bw.write(first_row,0,13);
    bw.newLine();

    Iterator n = m_keys.iterator();
    String name_prot;
    String lname_prot;
    String sequence_prot;
    int index=0;
    int tmp;
    int amino_acids_left=value.length();
    int amino_acids_read=0;
    int order_index=0;
    //Write the first lines (where name and protein share lines)
    //Check that the file contains more then 50 (content on one row)

    if(amino_acids_left > 50)
    {
      while(order_index < nr.intValue()){
        //Write name which is hopefully 11 chars or less
        name_prot = (String) lst.get(order_index);
        order_index++;
        lname_prot = new String(name_prot);
        if(lname_prot.length()>10){
        	lname_prot=lname_prot.substring(0, 10);
        }
        while(lname_prot.length()<11)
          lname_prot = lname_prot.concat(" ");
        bw.write(lname_prot);

        sequence_prot = new String((String)m.get(name_prot));
        while(index<5){
          bw.write(sequence_prot, index*10,10);
          bw.write(" ");
          index++;
        }
        index=0;
        bw.newLine();
      }
      //line_feed between amino acid groups
      bw.newLine();
      amino_acids_left -=50;
      amino_acids_read +=50;
      order_index=0;

      while(amino_acids_left > 50){

        while(order_index < nr.intValue()){
          name_prot = (String) lst.get(order_index);
          order_index++;
          sequence_prot = new String((String)m.get(name_prot));
          bw.write("           ");
          while(index<5){
            bw.write(sequence_prot, amino_acids_read + index*10,10);
            if(!((amino_acids_left == 50) && index == 4))
              bw.write(" ");
            index++;
          }
          index=0;
          bw.newLine();
        }
        amino_acids_left -=50;
        amino_acids_read +=50;
        bw.newLine();
        order_index=0;
      }

      //take care if there exist some more aminoacids
      if(amino_acids_left > 0){

        n = m_keys.iterator();
        while(order_index < nr.intValue()){
          name_prot = (String) lst.get(order_index);
          order_index++;
          sequence_prot = new String((String)m.get(name_prot));
          bw.write("           ");
          int floor=(int)(amino_acids_left/10);
          while(index<floor){
            bw.write(sequence_prot, amino_acids_read + index*10,10);
            if(!((amino_acids_left == (floor*10)) && index == (floor-1)))
              bw.write(" ");
            index++;
          }
          index=0;

          int start_read_at = amino_acids_read + floor*10;
          tmp = value.length() - start_read_at;
          while(tmp > 0){
            bw.write(sequence_prot, start_read_at + amino_acids_left -floor*10 -tmp,1);
            tmp--;
          }
          bw.newLine();
          tmp=0;
        }
      }
      bw.flush();
    }
    //less than 50 aminoacids in proteins
    else{
      order_index = 0;

      while(order_index < nr.intValue()){
        //Write name which is hopefully 11 chars or less
        name_prot = (String) lst.get(order_index);
        order_index++;

        lname_prot = new String(name_prot);
        while(lname_prot.length()<11)
          lname_prot = lname_prot.concat(" ");
        bw.write(lname_prot);

        //write the aminoacids
        sequence_prot = new String((String)m.get(name_prot));
        int floor=(int)(amino_acids_left/10);
        while(index<floor){
          bw.write(sequence_prot, amino_acids_read + index*10,10);
          if(!((amino_acids_left == (floor*10)) && index == (floor-1)))
            bw.write(" ");
          index++;
        }
        index=0;

        int start_read_at = amino_acids_read + floor*10;
        tmp = value.length() - start_read_at;
        while(tmp > 0){
          bw.write(sequence_prot, start_read_at + amino_acids_left -floor*10 -tmp,1);
          tmp--;
        }
        bw.newLine();
        tmp=0;
      }

      bw.flush();
    }


  }
  catch(IOException e)
  {
    System.out.println("Couldn't store the file");
  }


}


private static void write_fasta_formated(Map m,List lst,String file){
  String ofile = file.substring( 0, file.length()-4 );
  String end = file.substring( file.length()-4, file.length() );
  if( end.equals(".seq") == true ){
    System.out.println("Input filname suffix was .phy, outputfilesuffix of new file is .andor");
    ofile = ofile.concat(".fasta");
  }
  else{
    ofile = ofile.concat(".seq");
  }
  try
  {
  BufferedWriter bw = new BufferedWriter(new FileWriter(ofile));
  //write nr of proteins and their length
  //get number through map
  Integer nr= new Integer(m.size());
  String nr_prot = nr.toString();
  String name_prot;
  String sequence_prot;
  int order_index=0;

  while(order_index < nr.intValue()){
    name_prot = (String) lst.get(order_index);
    sequence_prot = new String((String)m.get(name_prot));
    bw.write(">" +name_prot);
    bw.newLine();
    bw.write(sequence_prot);
    bw.newLine();
    order_index++;
  }
  bw.flush();
  }
  catch(IOException e)
  {
  System.out.println("Couldn't store the file");
  }
}

private static void write_fasta_unformated(Map m,List lst,String file){
  String ofile = file.substring( 0, file.lastIndexOf(".") );
  String end = file.substring( file.lastIndexOf("."), file.length() );
  if( end.equals(".seq") == true ){
    System.out.println("Input filname suffix was .seq, outputfilesuffix of new file is .andor");
    ofile = ofile.concat(".andor");
    System.out.println("Created:" +ofile);
  }
  else{
    ofile = ofile.concat(".seq");
    System.out.println("Created:" +ofile);
  }
  try
  {
  BufferedWriter bw = new BufferedWriter(new FileWriter(ofile));
  //write nr of proteins and their length
  //get number through map
  Integer nr= new Integer(m.size());
  String nr_prot = nr.toString();
  String name_prot;
  String sequence_prot;
  int order_index=0;
  while(order_index < nr.intValue()){
    name_prot = (String) lst.get(order_index);
    sequence_prot = new String( (String)m.get(name_prot));
    sequence_prot = sequence_prot.replaceAll("-","");
    bw.write(">" +name_prot);
    bw.newLine();
    bw.write(sequence_prot);
    bw.newLine();
    order_index++;
  }
  bw.flush();
  }
  catch(IOException e)
  {
  System.out.println("Couldn't store the file");
  }
}

public static void main(String [] args){
  Map m = new HashMap();
  List lst = new ArrayList();//order of objects
  //stored with names in Strings (same
  System.out.println("What kind of file do you want to read from?");
  System.out.println("1. Rose");
  System.out.println("2. Phylip");
  System.out.println("3. Fasta");
  try{
    BufferedReader b = new BufferedReader( new InputStreamReader(System.in));
    String s = b.readLine();
    if(s.length() != 1)
      return;
    int i = Integer.parseInt(s);
    System.out.println("Write name of inputfile:");
    String file = b.readLine();
    if(file.length() == 0)
      return;
    if(i==1)
      read_rose(m,lst,file);
    if(i==2)
      read_phy(m,lst,file);
    if(i==3)
      read_fasta(m,lst,file);
    System.out.println("Do you want to mark TM regions in the sequences?");
    System.out.println("1. Yes");
    System.out.println("2. No");
    s = b.readLine();
    i = Integer.parseInt(s);
    if ( i == 1 ){
      find_tm(m,lst);
    }
    /*System.out.println("Do you want to translate DNA to amino acids in the sequences?");
    System.out.println("1. Yes");
    System.out.println("2. No");
    s = b.readLine();
    i = Integer.parseInt(s);
    if ( i == 1 ){
      translate(m,lst);
    }*/
    System.out.println("What format do you want to save the data in?");
    System.out.println("1. Phylip");
    System.out.println("2. Fasta with '-')");
    System.out.println("3. Fasta without '-')");
    s = b.readLine();
    if(s.length() != 1)
      return;
    i = Integer.parseInt(s);
    if(i==1)
      write_phy(m,lst,file);
    if(i==2)
      write_fasta_formated(m,lst,file);
    if(i==3)
      write_fasta_unformated(m,lst,file);
  }
  catch(IOException e){
    System.out.println("Couldn't open file");
  }
}

}


